﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.DirectX.DirectSound;

namespace SpeechToText.STT
{
    public class WavResource
    {        
        #region Public Values
        /// <summary> Данные о записи </summary>
        public WaveFormat WaveFormat { get; private set; }
        /// <summary> "Чистая" информация с микрофона </summary>
        public byte[] Data { get; private set; }
        #endregion
        
        #region Constructors

        public WavResource(WaveFormat format, byte[] data)
        {
            WaveFormat = format;
            Data = data;

        }

        public WavResource(string FilePath)
        {
            if (!File.Exists(FilePath)) throw new ArgumentException(@"Error: Incorrect file path or file not exist");
            FileStream FS = new FileStream(FilePath, FileMode.Open);

            byte[] Header = new byte[44];
            FS.Read(Header, 0, 44);
            WaveFormat = WavHeader.GetWavFormat(Header);

            Data = new byte[FS.Length];
            FS.Read(Data, 0, (int) FS.Length);

            FS.Close();
        }

        #endregion

        #region Public Methods

        public WavResource Join (WavResource WR)
        {
            if (!WaveFormat.Equals(WR.WaveFormat)) return null;

            byte[] NewData = new byte[Data.Length + WR.Data.Length];
            MemoryStream MS = new MemoryStream(NewData);
            MS.Write(Data, 0, Data.Length);
            MS.Write(WR.Data, 0, WR.Data.Length);
            MS.Close();

            return new WavResource(WaveFormat, NewData);
        }

        public void SaveToFile(string FilePath)
        {
            if (!FilePath.Contains('\\') && !FilePath.ToLower().EndsWith(".wav"))
                throw new ArgumentException(@"Error: Incorrect file path.");

            if (File.Exists(FilePath))
            {
                FileStream FS = new FileStream(FilePath, FileMode.Truncate);
                byte[] B = ToArray();
                FS.Write(B, 0, B.Length);
                FS.Close();
            }
            else
                File.WriteAllBytes(FilePath, ToArray());
        }

        public byte[] ToArray()
        {
            byte[] Arr = new byte[44 + Data.Length];
            MemoryStream MS = new MemoryStream(Arr);
            MS.Write(WavHeader.MakeWavHeader(WaveFormat, Data.Length), 0, 44);
            MS.Write(Data, 0, Data.Length);
            MS.Close();

            return Arr;
        }

        public MemoryStream ToStream()
        {
            MemoryStream MS = new MemoryStream();

            MS.Write(WavHeader.MakeWavHeader(WaveFormat, Data.Length), 0, 44);
            MS.Write(Data, 0, Data.Length);

            return MS;
        }

        /// <summary>
        /// (только для одноканального 16 bit звука)
        ///  Определяет наличие звува в файле. Запись считается шумной если
        ///  к-во значений громкости большей чем MinNoiseAmplitude превышает количество PercentOfNoise
        /// </summary>
        /// <param name="MinNoiseAmplitude"> Порог громкости. В процентах [0..1] </param>
        /// <param name="PercentOfNoise">Количество значений превысивших порог громкости. В процентах [0..1]</param>
        /// <returns></returns>
        public bool isNoisy(double MinNoiseAmplitude, double PercentOfNoise)
        {
            if ( (MinNoiseAmplitude < 0) || (MinNoiseAmplitude > 1) || (PercentOfNoise < 0) || (PercentOfNoise > 1) )
                throw new ArgumentException(@"Error: MinNoiseAmplitude or PercentOfNoise not in [0..1]");

            int count = 0;            
            int Amplitude = (int) (Int16.MaxValue * MinNoiseAmplitude);
            int Percent = (int) (Data.Length * PercentOfNoise);

            int wavStartInd = 0;
            bool NoisyWave = false;

            for (int i = 2; i < Data.Length; i += 2)
            {
                int ss = BitConverter.ToInt16(Data, i);
                if (BitConverter.ToInt16(Data, i) * BitConverter.ToInt16(Data, i - 2) <= 0)
                {
                    // если волна пересекла ось икс                    
                    if (NoisyWave)
                        count += (i - wavStartInd) * 2;

                    wavStartInd = i;
                    NoisyWave = false;
                }

                if ((BitConverter.ToInt16(Data, i) > Amplitude) && (!NoisyWave)) 
                    NoisyWave = true;

                if (count > Percent) 
                    return true;
            }

            return false;
        }

        #endregion
    }
}
